using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.Text;

namespace Microsoft.SqlServer.Tools.PublishWizard.CommandLine
{
	internal class Parser
	{
		private struct ArgumentHelpStrings
		{
			public string title;

			public bool isTitle;

			public string syntax;

			public string help;

			public ArgumentHelpStrings(string syntax, string help)
			{
				this.syntax = syntax;
				this.help = help;
				this.title = "";
				this.isTitle = false;
			}

			public ArgumentHelpStrings(string titleString)
			{
				this.syntax = "";
				this.help = "";
				this.title = titleString;
				this.isTitle = true;
			}
		}

		public const string NewLine = "\r\n";

		private const int spaceBeforeParam = 2;

		private const int STD_OUTPUT_HANDLE = -11;

		private ArrayList arguments;

		private Hashtable argumentMap;

		private Argument defaultArgument;

		private ErrorReporter reporter;

		public bool HasDefaultArgument
		{
			get
			{
				return this.defaultArgument != null;
			}
		}

		private Parser()
		{
		}

		public Parser(Type argumentSpecification, ErrorReporter reporter)
		{
			this.reporter = reporter;
			this.arguments = new ArrayList();
			this.argumentMap = new Hashtable();
			if (argumentSpecification != null)
			{
				PropertyInfo[] properties = argumentSpecification.GetProperties();
				for (int i = 0; i < properties.Length; i++)
				{
					PropertyInfo propertyInfo = properties[i];
					ArgumentAttribute attribute = Parser.GetAttribute(propertyInfo);
					if (attribute.IsDefaultArgument)
					{
						this.defaultArgument = new Argument(attribute, propertyInfo, reporter);
					}
					else
					{
						this.arguments.Add(new Argument(attribute, propertyInfo, reporter));
					}
				}
				foreach (Argument argument in this.arguments)
				{
					this.argumentMap[argument.LongName] = argument;
					if (argument.ExplicitShortName)
					{
						if (argument.ShortName != null && argument.ShortName.Length > 0)
						{
							this.argumentMap[argument.ShortName] = argument;
						}
						else
						{
							argument.ClearShortName();
						}
					}
				}
				foreach (Argument argument2 in this.arguments)
				{
					if (!argument2.ExplicitShortName)
					{
						if (argument2.ShortName != null && argument2.ShortName.Length > 0 && !this.argumentMap.ContainsKey(argument2.ShortName))
						{
							this.argumentMap[argument2.ShortName] = argument2;
						}
						else
						{
							argument2.ClearShortName();
						}
					}
				}
			}
		}

		public static int GetConsoleWindowWidth()
		{
			CONSOLE_SCREEN_BUFFER_INFO cONSOLE_SCREEN_BUFFER_INFO = default(CONSOLE_SCREEN_BUFFER_INFO);
			UnsafeNativeMethods.GetConsoleScreenBufferInfo(UnsafeNativeMethods.GetStdHandle(-11), ref cONSOLE_SCREEN_BUFFER_INFO);
			return (int)cONSOLE_SCREEN_BUFFER_INFO.dwSize.x;
		}

		public static bool ParseArgumentsWithUsage(string[] arguments, object destination, string sytax)
		{
			if (Parser.ParseHelp(arguments))
			{
				Console.Write(Parser.ArgumentsUsage(null, sytax));
				return false;
			}
			if (!Parser.ParseArguments(arguments, destination))
			{
				Console.Write(Parser.ArgumentsUsage(destination.GetType(), sytax));
				return false;
			}
			return true;
		}

		public static bool ParseArguments(string[] arguments, object destination)
		{
			return Parser.ParseArguments(arguments, destination, new ErrorReporter(Console.Error.WriteLine));
		}

		public static bool ParseArguments(string[] arguments, object destination, ErrorReporter reporter)
		{
			Parser parser = new Parser(destination.GetType(), reporter);
			return parser.Parse(arguments, destination);
		}

		public static string ArgumentsUsage(Type argumentType, List<string> syntaxs)
		{
			int num = Parser.GetConsoleWindowWidth();
			if (num == 0)
			{
				num = 80;
			}
			return Parser.ArgumentsUsage(argumentType, num, syntaxs);
		}

		public static string ArgumentsUsage(Type argumentType, string syntax)
		{
			return Parser.ArgumentsUsage(argumentType, new List<string>
			{
				syntax
			});
		}

		public static string ArgumentsUsage(Type argumentType, int columns, List<string> syntaxs)
		{
			return new Parser(argumentType, null).GetUsageString(columns, syntaxs);
		}

		public static bool ParseHelp(string[] args)
		{
			Parser parser = new Parser(typeof(HelpArgument), new ErrorReporter(Parser.NullErrorReporter));
			HelpArgument helpArgument = new HelpArgument();
			parser.Parse(args, helpArgument);
			return helpArgument.help;
		}

		public static int IndexOf(StringBuilder text, char value, int startIndex)
		{
			for (int i = startIndex; i < text.Length; i++)
			{
				if (text[i] == value)
				{
					return i;
				}
			}
			return -1;
		}

		public static int LastIndexOf(StringBuilder text, char value, int startIndex)
		{
			for (int i = Math.Min(startIndex, text.Length - 1); i >= 0; i--)
			{
				if (text[i] == value)
				{
					return i;
				}
			}
			return -1;
		}

		public bool Parse(string[] args, object destination)
		{
			bool flag = this.ParseArgumentList(args, destination);
			foreach (Argument argument in this.arguments)
			{
				flag |= argument.Finish(destination);
			}
			if (this.defaultArgument != null)
			{
				flag |= this.defaultArgument.Finish(destination);
			}
			return !flag;
		}

		public string GetUsageString(int screenWidth, List<string> syntaxes)
		{
			List<Parser.ArgumentHelpStrings> allHelpStrings = this.GetAllHelpStrings(syntaxes);
			int num = 0;
			foreach (Parser.ArgumentHelpStrings current in allHelpStrings)
			{
				num = Math.Max(num, current.syntax.Length);
			}
			int num2 = num + 2;
			screenWidth = Math.Max(screenWidth, 15);
			int num3;
			if (screenWidth < num2 + 10)
			{
				num3 = 5;
			}
			else
			{
				num3 = num2;
			}
			StringBuilder stringBuilder = new StringBuilder();
			foreach (Parser.ArgumentHelpStrings current2 in allHelpStrings)
			{
				if (current2.isTitle)
				{
					stringBuilder.Append(current2.title);
					stringBuilder.Append("\n");
				}
				else
				{
					int length = current2.syntax.Length;
					stringBuilder.Append("  " + current2.syntax);
					int num4 = length;
					if (length >= num3)
					{
						stringBuilder.Append("\n");
						num4 = 0;
					}
					int num5 = screenWidth - num3;
					int i = 0;
					if (!string.IsNullOrEmpty(current2.help))
					{
						while (i < current2.help.Length)
						{
							stringBuilder.Append(' ', num3 - num4);
							num4 = num3;
							int num6 = i + num5;
							if (num6 >= current2.help.Length)
							{
								num6 = current2.help.Length;
							}
							else
							{
								num6 = current2.help.LastIndexOf(' ', num6 - 1, Math.Min(num6 - i, num5));
								if (num6 <= i)
								{
									num6 = i + num5;
								}
							}
							stringBuilder.Append(current2.help, i, num6 - i);
							i = num6;
							Parser.AddNewLine("\n", stringBuilder, ref num4);
							while (i < current2.help.Length && current2.help[i] == ' ')
							{
								i++;
							}
						}
					}
					if (string.IsNullOrEmpty(current2.help))
					{
						stringBuilder.Append("\n");
					}
				}
			}
			return stringBuilder.ToString();
		}

		internal static string LongName(ArgumentAttribute attribute, PropertyInfo field)
		{
			if (attribute != null && !attribute.DefaultLongName)
			{
				return attribute.LongName;
			}
			return field.Name;
		}

		internal static string ShortName(ArgumentAttribute attribute, PropertyInfo field)
		{
			if (attribute.IsDefaultArgument)
			{
				return null;
			}
			if (!Parser.ExplicitShortName(attribute))
			{
				return Parser.LongName(attribute, field).Substring(0, 1);
			}
			return attribute.ShortName;
		}

		internal static string HelpText(ArgumentAttribute attribute)
		{
			if (attribute == null)
			{
				return null;
			}
			return attribute.HelpText;
		}

		internal static string HelpTopic(ArgumentAttribute attribute)
		{
			if (attribute == null)
			{
				return null;
			}
			return attribute.HelpTopic;
		}

		internal static string ArgumentHelpText(ArgumentAttribute attribute)
		{
			if (attribute == null)
			{
				return null;
			}
			return attribute.ArgumentHelpText;
		}

		internal static bool HasHelpText(ArgumentAttribute attribute)
		{
			return attribute != null && attribute.HasHelpText;
		}

		internal static bool ExplicitShortName(ArgumentAttribute attribute)
		{
			return attribute != null && !attribute.DefaultShortName;
		}

		internal static object DefaultValue(ArgumentAttribute attribute)
		{
			if (attribute != null && attribute.HasDefaultValue)
			{
				return attribute.DefaultValue;
			}
			return null;
		}

		internal static Type ElementType(ArgumentAttribute attribute, PropertyInfo property)
		{
			if (Parser.IsCollectionType(property.PropertyType))
			{
				return attribute.ElementType;
			}
			return null;
		}

		internal static short MaxNumberOfArguments(ArgumentAttribute attribute)
		{
			return attribute.MaxNumberOfArguments;
		}

		internal static ArgumentTypes Flags(ArgumentAttribute attribute, PropertyInfo property)
		{
			if (attribute != null)
			{
				return attribute.Type;
			}
			if (Parser.IsCollectionType(property.PropertyType))
			{
				return ArgumentTypes.MultipleUnique;
			}
			return ArgumentTypes.AtMostOnce;
		}

		internal static bool IsCollectionType(Type type)
		{
			return type == typeof(ArrayList);
		}

		internal static bool IsValidElementType(Type type)
		{
			return type != null && (type == typeof(int) || type == typeof(uint) || type == typeof(string) || type == typeof(bool) || type.IsEnum);
		}

		private static void NullErrorReporter(string message)
		{
		}

		private static ArgumentAttribute GetAttribute(PropertyInfo field)
		{
			object[] customAttributes = field.GetCustomAttributes(typeof(ArgumentAttribute), false);
			if (customAttributes.Length == 1)
			{
				return (ArgumentAttribute)customAttributes[0];
			}
			return null;
		}

		private static void AddNewLine(string newLine, StringBuilder builder, ref int currentColumn)
		{
			builder.Append(newLine);
			currentColumn = 0;
		}

		private static Parser.ArgumentHelpStrings GetHelpStrings(Argument arg)
		{
			return new Parser.ArgumentHelpStrings(arg.SyntaxHelp, arg.FullHelpText);
		}

		private void ReportUnrecognizedArgument(string argument)
		{
			this.reporter(string.Format(CultureInfo.CurrentCulture, CommandLineResources.UnRecognizedCommand, new object[]
			{
				argument
			}));
		}

		private bool ParseArgumentList(string[] args, object destination)
		{
			bool flag = false;
			short num = 0;
			bool flag2 = false;
			if (args != null)
			{
				for (int i = 0; i < args.Length; i++)
				{
					string text = args[i];
					if (text.Length > 0)
					{
						switch (text[0])
						{
						case '-':
						case '/':
						{
							string key = text.Substring(1);
							string value = null;
							Argument argument = (Argument)this.argumentMap[key];
							if (argument != null)
							{
								if (argument.ValueType == typeof(string) && i < args.Length - 1)
								{
									string text2 = args[i + 1];
									if (text2.Length > 0)
									{
										value = text2;
										i++;
									}
								}
								flag |= !argument.SetValue(value, destination);
								goto IL_169;
							}
							if (this.defaultArgument != null && num < this.defaultArgument.MaxNumberOfArguments)
							{
								flag |= !this.defaultArgument.SetValue(text, destination);
								num += 1;
								goto IL_169;
							}
							if (!flag2)
							{
								this.ReportUnrecognizedArgument(text);
								flag = true;
								flag2 = true;
								goto IL_169;
							}
							goto IL_169;
						}
						}
						if (this.defaultArgument != null)
						{
							flag |= !this.defaultArgument.SetValue(text, destination);
							num += 1;
							if (num == this.defaultArgument.MaxNumberOfArguments + 1)
							{
								this.reporter(string.Format(CultureInfo.CurrentCulture, CommandLineResources.ERROR_WrongNumberOfArguments, new object[]
								{
									text
								}));
								flag = true;
							}
						}
						else
						{
							this.ReportUnrecognizedArgument(text);
							flag = true;
						}
					}
					IL_169:;
				}
			}
			return flag;
		}

		private List<Parser.ArgumentHelpStrings> GetAllHelpStrings(List<string> syntaxes)
		{
			List<Parser.ArgumentHelpStrings> list = new List<Parser.ArgumentHelpStrings>();
			list.Add(new Parser.ArgumentHelpStrings("\n" + CommandLineResources.Usage + ":", ""));
			foreach (string current in syntaxes)
			{
				list.Add(new Parser.ArgumentHelpStrings("\n" + current + "\n"));
			}
			if (this.arguments.Count > 0)
			{
				list.Add(new Parser.ArgumentHelpStrings(CommandLineResources.Switch + ":\n"));
			}
			string strA = "";
			foreach (Argument argument in this.arguments)
			{
				if (!string.IsNullOrEmpty(argument.HelpTopic) && string.Compare(strA, argument.HelpTopic, StringComparison.CurrentCulture) != 0)
				{
					list.Add(new Parser.ArgumentHelpStrings("\n " + argument.HelpTopic + ":\n"));
					strA = argument.HelpTopic;
				}
				list.Add(Parser.GetHelpStrings(argument));
			}
			return list;
		}
	}
}
